'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with self work for additional information
 * regarding copyright ownership.  The ASF licenses self file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use self file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.graph import Node_ANY
from base.graph.Node import Node
from base.graph.Triple import Triple

from base.java.Objects import Objects

# import java.util.Objects;
# import java.util.stream.Stream;

# import org.apache.jena.atlas.iterator.Iter;
# import org.apache.jena.graph.impl.GraphBase;
# import org.apache.jena.shared.AddDeniedException;
# import org.apache.jena.shared.DeleteDeniedException;
# import org.apache.jena.shared.PrefixMapping;
# import org.apache.jena.util.iterator.ExtendedIterator;
# import org.apache.jena.util.iterator.NullIterator;

'''
 * The interface to be satisfied by implementations maintaining collections
 * of RDF triples. The core interface is small (add, delete, find, contains) and
 * is augmented by additional classes to handle more complicated matters
 * such as event management.
 *
 * @see GraphBase for an implementation framework.
'''
from abc import ABC, abstractmethod


class Graph(ABC):
    '''
     * An immutable empty graph.
    '''
    # param 
    # result static final Graph

    '''
     * True if self graph's content depends on the other graph. May be
     * pessimistic (ie return True if it's not sure). Typically True when a
     * graph is a composition of other graphs, eg union.
     *
     * @param other the graph self graph may depend on
     * @return False if self does not depend on other
    '''

    # param Graph other
    # result boolean
    @abstractmethod
    def dependsOn(self, other):
        pass

    '''
     * returns self Graph's transaction handler
    '''
    # param 
    # result TransactionHandler
    # @abstractmethod
    # def getTransactionHandler(self):
    #     pass

    '''
     * returns self Graph's capabilities
    '''
    # param 
    # result Capabilities
    # @abstractmethod
    # def getCapabilities(self):
    #     pass

    '''
     * Answer self Graph's event manager.
    '''
    # param 
    # result GraphEventManager
    # @abstractmethod
    # def getEventManager(self):
    #     pass

    '''
     * returns self Graph's prefix mapping. Each call on a given Graph gets the
     * same PrefixMapping object, which is the one used by the Graph.
    '''

    # param
    # result PrefixMapping
    @abstractmethod
    def getPrefixMapping(self):
        pass

    '''
     * Add the triple t (if possible) to the set belonging to self graph
     *
     * @param t the triple to add to the graph
     * @throws AddDeniedException if the triple cannot be added
    '''

    # param Triple t
    # result void
    @abstractmethod
    def add(self, t):
        pass

    '''
     * Add the triple comprised of s,p,o to the set belonging to self graph
     *
     * @throws AddDeniedException if the triple cannot be added
    '''

    # param Node s, Node p, Node o
    # result default
    @abstractmethod
    def addSPO(self, s, p, o):
        Objects.requireNonNull(s, "Subject must not be null")
        Objects.requireNonNull(p, "Predicate must not be null")
        Objects.requireNonNull(o, "Object must not be null")
        self.add(Triple.create(s, p, o))

    '''
     * Delete the triple t (if possible) from the set belonging to self graph
     *
     * @param t the triple to delete to the graph
     * @throws DeleteDeniedException if the triple cannot be removed
    '''

    # param Triple t
    # result void
    @abstractmethod
    def delete(self, t):
        pass

    '''
     * Delete the triple comprised of s,p,o from the set belonging to self graph
     *
     * @throws AddDeniedException if the triple cannot be added
    '''

    # param Node s, Node p, Node o
    # result default
    @abstractmethod
    def deleteSPO(self, s, p, o):
        Objects.requireNonNull(s, "Subject must not be null")
        Objects.requireNonNull(p, "Predicate must not be null")
        Objects.requireNonNull(o, "Object must not be null")
        self.delete(Triple.create(s, p, o))

    '''
     * Returns an iterator over all the Triples that match the triple pattern.
     *
     * @param m a Triple encoding the pattern to look for
     * @return an iterator of all triples in self graph that match m
    '''

    # param Triple
    # ExtendedIterator<Triple>
    @abstractmethod
    def find(self, m):
        pass

    '''
     * Returns an iterator over Triples matching a pattern.
     *
     * @return an iterator of triples in self graph matching the pattern.
    '''

    # param Triple
    # ExtendedIterator<Triple>
    @abstractmethod
    def findSPO(self, s, p, o):
        pass

    '''
     * Returns a:@link Stream of Triples matching a pattern.
     *
     * @return a stream  of triples in self graph matching the pattern.
    '''
    # param Node s, Node p, Node o
    # result default
    # @abstractmethod
    # def Stream<Triple> stream(self, s, p, o):
    #     pass:
    # # param s, p, o):
    #     pass
    # # result return
    # @abstractmethod
    # def Iter.asStream(find(self):
    #     pass

    '''
     * Returns a:@link Stream of all triples in the graph.
     *
     * @return a stream  of triples in self graph.
    '''
    # param 
    # result default
    # @abstractmethod
    # def Stream<Triple> stream(self):
    #     pass:
    # # param Node_ANY.ANY, Node_ANY.ANY, Node_ANY.ANY
    # # result return
    # @abstractmethod
    # def stream(self):
    #     pass

    '''
     * Returns an iterator over all Triples in the graph.
     * Equivalent to:@code find(Node_ANY.ANY, Node_ANY.ANY, Node_ANY.ANY)
     *
     * @return an iterator of all triples in self graph
    '''

    # param
    # result ExtendedIterator
    @abstractmethod
    def findAll(self):
        return self.findSPO(Node_ANY.ANY, Node_ANY.ANY, Node_ANY.ANY)

    '''
     * Compare self graph with another using the method
     * described in
     * <a href="http:#www.w3.org/TR/rdf-concepts#section-Graph-syntax">
     * http:#www.w3.org/TR/rdf-concepts#section-Graph-syntax
     * </a>
     * <p>
     * Note: self implementation does not handle correctly blank nodes in
     * quoted triples (RDF-star). If you need to work with RDF-star,
     * use the slower implementation in
     *:@code org.apache.jena.sparql.util.IsoMatcher.
     *
     * @param g Compare against self.
     * @return boolean True if the two graphs are isomorphic.
    '''

    # param Graph g
    # result boolean
    @abstractmethod
    def isIsomorphicWith(self, g):
        pass

    '''
     * Answer True iff the graph contains a triple matching (s, p, o).
     * s/p/o may be concrete or fluid. Equivalent to find(s,p,o).hasNext,
     * but an implementation is expected to optimise self in easy cases.
    '''

    # param Node s, Node p, Node o
    # result boolean
    @abstractmethod
    def containsSPO(self, s, p, o):
        pass

    '''
     * Answer True iff the graph contains a triple that t matches t may be
     * fluid.
    '''

    # param Triple t
    # result boolean
    @abstractmethod
    def contains(self, t):
        pass

    '''
     * Remove all the statements from self graph.
    '''

    # param
    # result void
    @abstractmethod
    def clear(self):
        pass

    '''
     * Remove all triples that match by find(s, p, o)
    '''

    # param Node s, Node p, Node o
    # result void
    @abstractmethod
    def remove(self, s, p, o):
        pass

    '''
     * Free all resources, any further use of self Graph is an error.
    '''

    # param
    # result void
    @abstractmethod
    def close(self):
        pass

    '''
     * Answer True iff self graph is empty. "Empty" means "has as few triples as it
     * can manage", because an inference graph may have irremovable axioms
     * and their consequences.
    '''

    # param
    # result boolean
    @abstractmethod
    def isEmpty(self):
        pass

    '''
     * For a concrete graph self returns the number of triples in the graph. For graphs which
     * might infer additional triples it results an estimated lower bound of the number of triples.
     * For example, an inference graph might return the number of triples in the raw data graph.
    '''

    # param
    # result int
    @abstractmethod
    def size(self):
        pass

    '''
     * Answer True iff .close() has been called on self Graph.
    '''

    # param
    # result boolean
    @abstractmethod
    def isClosed(self):
        pass



